<?php

/**
 * descript:
 * User: blue
 * Date: 2018/6/8 9:29
 */

namespace app\api\service;

use app\lib\enum\PayEnum;
use app\lib\exception\OrderException;
use app\lib\exception\TokenException;
use think\Exception;
use think\facade\Env;
use think\facade\Log;

//引入微信支付sdk,没有命名空间
require_once Env::get('root_path') . 'extend/WxPay/WxPay.Api.php';

class PayS
{
    //为什么要这两个成员属性,不是有一个就够了吗?
    private $orderID;
    private $orderNO;

    public function __construct($orderID)
    {
        if(!$orderID){
            throw new Exception("订单号不允许为null");
        }
        $this->orderID=$orderID;
    }

    /**
     * 订单支付方法
     * @throws OrderException
     */
    public function Pay(){
        /*支付前的检测
         * paycountDetect 检测订单号不存在,订单号和用户不一致,订单不是未支付状态
         * getOrderStock 订单库存量检测*/
        $this->payCountDetect($this->orderID);
        $status=(new Order())->getOrderStock($this->orderID);
        if(!$status['pass']){
            throw new OrderException(['msg'=>'库存量检测失败']);
        }
        //调用微信预支付方法
        return $this->orderPrePay($status['orderPrice']);
    }

    //订单预支付
    private function orderPrePay($totalPrice){
        //根据token获取openid
        $openId=Token::tokenGetInfo('openid');
        if(!$openId){
            throw new TokenException();
        }
        $wxObj=new \WxPayUnifiedOrder();
        //订单号
        $wxObj->SetOut_trade_no($this->orderNO);
        //订单价格
        $wxObj->SetTotal_fee($totalPrice*100);
        // $wxObj->SetTime_start(date("YmdHis"));
        // $wxObj->SetTime_expire(date("YmdHis", time() + 600));
        // $wxObj->SetGoods_tag("test");
        //设置商品和支付单描述
        $wxObj->SetBody("test");
        //交易回调地址,有两种选择:1.在config中配置,另一种在方法中配置,这个必须是互联网地址
        $wxObj->SetNotify_url(config('weixin.notice_url'));
        //交易类型
        $wxObj->SetTrade_type("JSAPI");
        //交易对应的openid号
        $wxObj->SetOpenid($openId);
        //调用微信预支付接口
        return $this->wxPrepay($wxObj);
    }

    /**
     * 统一下单，WxPayUnifiedOrder中out_trade_no、body、total_fee、trade_type必填(openid)
     * appid、mchid、spbill_create_ip、nonce_str不需要填入
     * @param $wxObjWxPayUnifiedOrder
     */
    private function wxPrepay($wxObj){
        $res=\WxPayApi::unifiedOrder($wxObj);
        //如果支付失败,写入日志中
        if($res['return_code']!="SUCCESS"&&$res['result_code']!="SUCCESS"){
            Log::write("微信支付失败".$res['return_msg'],'error');
        }
        //如果成功,更新order表中的prepay_id,并按照格式返回微信需要的状态码
        \app\api\model\Order::where('id',$this->orderID)->update(['prepay_id'=>$res['prepay_id']]);
        return $this->wxPayment($res);

    }

    /**
     * 微信支付返回格式
     */
    private function wxPayment($res){
        /*timeStamp	String	是	时间戳从1970年1月1日00:00:00至今的秒数,即当前的时间.
        nonceStr	String	是	随机字符串，长度为32个字符以下。
        package	String	是	统一下单接口返回的 prepay_id 参数值，提交格式如：prepay_id=*
        signType	String	是	签名算法，暂支持 MD5
        paySign	String	是	签名,具体签名方案参见小程序支付接口文档;*/
        $obj=new \WxPayJsApiPay();
        $obj->SetAppid(config('weixin.app_id'));
        $obj->SetTimeStamp((string)time());
        //生成32位随机数
        $rand=md5(microtime().mt_rand(0,10000));
        $obj->SetNonceStr($rand);
        $obj->SetPackage("prepay_id=".$res['prepay_id']);
        $obj->SetSignType("MD5");
        //sdk的生成签名函数
        $sign=$obj->MakeSign();
        //获取微信支付返回参数
        $payStatus=$obj->GetValues();
        $payStatus['paySign']=$sign;
        return $payStatus;
    }

    /**
     * 支付之前的订单检测
     * 1.订单号不存在
     * 2.订单号存在,但是和当前用户是不匹配的
     * 3.订单有可能被支付过
     * @param $id
     * @throws Exception
     * @throws OrderException
     * @throws TokenException
     */
    private  function payCountDetect($id){
        //判断订单是否存在
        $res=\app\api\model\Order::get($id);
        if(!$res){
            throw new OrderException();
        }
        //判断用户不一致的情况
        if(!Token::UserSame($res->user_id)){
            throw new  TokenException(['msg'=>'订单与用户不匹配']);
        }
        //判断订单是否支付过
        if($res->status!=PayEnum::UNPAID){
            throw new Exception("订单支付状态异常");
        }
        //订单状态检测通过,设置订单编号
        $this->orderNO=$res->order_no;
        return true;
    }


}